package com.yupi.tangoj.judgeservice;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yupi.tangoj.codebox.CodeSandBox;
import com.yupi.tangoj.codebox.SandBoxParam;
import com.yupi.tangoj.codebox.SandBoxVO;
import com.yupi.tangoj.codebox.design.SandBoxFactory;
import com.yupi.tangoj.common.ErrorCode;
import com.yupi.tangoj.exception.BusinessException;
import com.yupi.tangoj.model.dto.question.JudgeCase;
import com.yupi.tangoj.model.dto.question.JudgeConfig;
import com.yupi.tangoj.model.dto.questionsubmit.JudgeInfo;
import com.yupi.tangoj.model.entity.Question;
import com.yupi.tangoj.model.entity.QuestionSubmit;
import com.yupi.tangoj.service.QuestionService;
import com.yupi.tangoj.service.QuestionSubmitService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.yupi.tangoj.model.enums.QuestionSubmitStatusEnum.*;


@Service
public class JudgeServiceImpl implements JudgeService{

    @Autowired
    private QuestionSubmitService questionSubmitService;

    @Autowired
    private QuestionService questionService;

    @Value("${sand.type:comm}")
    public String type;

    @Override
    public JudgeContext judgeTitle(Long questionSubId) {

        //1.参数校验
        if (questionSubId == null || questionSubId < 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"questionSubId 错误");
        }
        //2.查询提交记录
        QuestionSubmit questionSubmit = questionSubmitService.getById(questionSubId);
        if (questionSubmit == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"questionSubmit 不存在");
        }

        //2.1 是否已经进入判题系统
        Integer status = questionSubmit.getStatus();
        if (!Objects.equals(status, WAITING.getValue())){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"判题中 请等待");
        }

        questionSubmit.setStatus(RUNNING.getValue());
        //2.1.1更改判题状态 为 判题中
        questionSubmitService.updateById(questionSubmit);

        //2.2 拿到输入输出用例等信息
        String language = questionSubmit.getLanguage();
        String code = questionSubmit.getCode();

        Long questionId = questionSubmit.getQuestionId();
        if (questionId == null || questionId <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"questionId 错误");
        }

        Question question = questionService.getById(questionId);
        if (question == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"question 不存在");
        }

        Long id = question.getId();
        String answer = question.getAnswer();
        JSONArray judgeCaseJSON = question.getJudgeCase();
        JSONObject judgeConfigJSON = question.getJudgeConfig();

        JudgeConfig judgeConfig = JSONUtil.toBean(judgeConfigJSON,JudgeConfig.class);
        List<JudgeCase> judgeCase = JSONUtil.toList(judgeCaseJSON,JudgeCase.class);

        //2.3整理想要的数据
        SandBoxParam sandBoxParam = new SandBoxParam();

        List<String> inputList = judgeCase.stream().map(JudgeCase::getInput).collect(Collectors.toList());
        List<String> outputList = judgeCase.stream().map(JudgeCase::getOutput).collect(Collectors.toList());

        sandBoxParam.setLanguage(language);
        sandBoxParam.setCode(code);
        sandBoxParam.setInput(inputList);

        //3.调用代码沙箱 判断判题状态
        CodeSandBox codeSandBox = SandBoxFactory.createCodeSanBox(type);

        SandBoxVO sandBoxVO = codeSandBox.executeCodeSandBox(sandBoxParam);

        //4.判断判题是否成功
        String boxMessage = sandBoxVO.getBoxMessage();
        JudgeInfo judgeInfo = sandBoxVO.getJudgeInfo();
        List<String> outputResult = sandBoxVO.getOutput();

        if (outputResult == null || outputResult.size() != outputList.size()){
            questionSubmit.setStatus(FAILED.getValue());
            questionSubmitService.updateById(questionSubmit);
            return new JudgeContext();
        }

        for (int i = 0; i < outputList.size(); i++) {
            if (!outputResult.get(i).equals(outputList.get(i))){
                questionSubmit.setStatus(FAILED.getValue());
                questionSubmitService.updateById(questionSubmit);
                return new JudgeContext();
            }
        }

        questionSubmit.setStatus(SUCCESS.getValue());
        questionSubmitService.updateById(questionSubmit);

        return new JudgeContext();
    }
}
